home *** CD-ROM | disk | FTP | other *** search
- #include <stdlib.h>
- #include <stdio.h>
- #include "cschlr.hpp"
-
- const int MAIN = CSC_NO_THREAD; //main prgram context
- const int DUMMY = MAIN + 1; //temporary context
- const int EMPTY =-1; //no delayed thread marker
-
- /* The following static varaible is used to facilitate the
- implementation of Kill. This limits the number of Cschlr
- object per Windows application to 1 only */
- static Cschlr *schlr;
-
- /* Used for the implicit termination of a thread when
- execution falls through the thread function body */
- static void Kill()
- {
- schlr->Suicide();
- }
-
-
- /* Used to check if it is time to wake up the sleeping
- threads. */
- void Cschlr::WakeUp()
- {
- time_t current;
- schlr_table *ptr;
-
- /* check time and dispatch thread */
- time(¤t);
- while ((head != EMPTY) &&
- (current >= (ptr = (table + head))->wakeuptime))
- {
- readyQ.Enqueue(head);
- head = ptr->next;
- ptr->next = EMPTY;
- }
- }
-
-
- /* Used to perform a task switch. Control is passed
- back to the Windows PeekMessage loop */
- void Cschlr::Switch(Csemq *sem)
- {
- WakeUp();
- sem->Enqueue(nRunning);
- task[nRunning]->Transfer(*task[MAIN]);
- }
-
-
- /* Constructor to set up the task table */
- Cschlr::Cschlr()
- {
- nTask = 0;
- nRunning = CSC_NO_THREAD;
- head = EMPTY;
- table = new schlr_table[CSC_NO_THREAD];
- schlr = this;
-
- //used to resume main program
- task[MAIN] = new Cthread(NULL, 0, NULL, 0);
-
- //used in Suicide to switch task
- task[DUMMY] = new Cthread(NULL, 0, NULL, 0);
- }
-
-
- /* Empty destructor */
- Cschlr::~Cschlr()
- {
- //do nothing
- }
-
-
- /* Used to create a thread and pass to it a user variable */
- int Cschlr::CreateThread(THDFN func, int stacksize, void *param)
- {
- THDFN retaddr; //these two variables must appear
- void *ptr; //together for CreateThread to work
- int i;
-
- int thread = CSC_NO_THREAD;
-
- if (nTask < CSC_NO_THREAD + 1)
- {
- for (i = 0; i < CSC_NO_THREAD + 1; i++)
- {
- if (task[i] == NULL)
- break;
- }
- retaddr = Kill; //set return address to point to Kill
- ptr = param; //set user parameter pointer
- task[i] = new Cthread(func, stacksize, (int *) &retaddr, 4);
- readyQ.Enqueue(i);
- thread = nTask++;
- }
-
- return (thread);
- }
-
-
- /* Used by a calling thread to commit suicide or
- self-terminate */
- void Cschlr::Suicide()
- {
- int current;
-
- current = nRunning;
- nRunning = readyQ.Dequeue();
- delete task[current];
- task[current] = NULL;
- nTask--;
- task[DUMMY]->Transfer(*task[nRunning]);
- }
-
-
- /* Used to create a semaphore object */
- Csemq* Cschlr::CreateSem(long lValue)
- {
- return (new Csemq(lValue));
- }
-
-
- /* Used to destroy a semaphore object */
- void Cschlr::DestroySem(Csemq* sem)
- {
- delete sem;
- }
-
-
- /* Used to signal a semaphore */
- void Cschlr::Signal(Csemq *sem, long lMaxCount)
- {
- if (sem->GetType() == CST_COUNT)
- {
- if (sem->GetCount() < lMaxCount)
- sem->UpdateCount(1);
- }
- else
- {
- readyQ.Enqueue(sem->Dequeue());
- }
- }
-
-
- /* Used to wait on a semaphore */
- void Cschlr::Wait(Csemq *sem)
- {
-
- if (sem->GetType() == CST_COUNT)
- {
- if (!sem->GetCount())
- {
- //move running thread to semaphore queue and
- //switch to a ready-to-run thread
- Switch(sem);
- }
- else
- //decrement sempahore count and continue execution
- sem->UpdateCount(-1);
- }
- else
- {
- //move running thread to semaphore queue and
- //switch to a ready-to-run thread
- Switch(sem);
- }
- }
-
-
- /* Used to give up the cpu voluntarily */
- void Cschlr::Preempt()
- {
- Switch(&readyQ);
- }
-
-
- /* Used to put the calling thread to sleep for the
- specified number of seconds */
- void Cschlr::Sleep(long lSeconds)
- {
- time_t current;
- schlr_table *ptr;
- schlr_table *thread;
- int prev;
- int next;
-
- current = time(0) + lSeconds; //init wakeup time
-
- if (head == EMPTY)
- { //no thread delayed
- head = nRunning;
- next = EMPTY;
- }
- else //scan delayed threads
- {
- prev = EMPTY;
- next = head;
- while ((next != EMPTY) && (current >=
- (ptr = (table + next))->wakeuptime))
- {
- prev = next;
- next = ptr->next;
- }
-
- if (prev == EMPTY)
- head = nRunning;
- else
- (table + prev)->next = nRunning;
- }
-
- ptr = (table + nRunning);
- ptr->wakeuptime = current;
- ptr->next = next;
-
- Switch(&waitQ);
-
- }
-
-
- /* Used to retrieve the status of a semaphore */
- void Cschlr::GetSemStates(Csemq *sem, long &lCount, int &fWait)
- {
- if (sem->GetType() == CST_COUNT)
- {
- lCount = sem->GetCount();
- fWait = 0;
- }
- else
- {
- lCount = 0;
- fWait = 1;
- }
- }
-
-
- /* Used by the main PeekMessage loop to multiplex the
- cpu among a number of threads */
- void Cschlr::Run()
- {
- if ((nRunning = readyQ.Dequeue()) != CSC_NO_THREAD)
- task[MAIN]->Transfer(*task[nRunning]);
- else
- WakeUp();
- }
-